const axios = require('axios');

class TiandituService {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrls = {
      // 影像底图
      image: 'https://t{s}.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}',
      // 影像注记
      imageLabel: 'https://t{s}.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}',
      // 矢量底图
      vector: 'https://t{s}.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}',
      // 矢量注记
      vectorLabel: 'https://t{s}.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}',
      // 地形底图
      terrain: 'https://t{s}.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}',
      // 地形注记
      terrainLabel: 'https://t{s}.tianditu.gov.cn/cta_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cta&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}'
    };
  }

  /**
   * 获取地图瓦片URL
   * @param {string} type - 地图类型
   * @param {number} z - 缩放级别
   * @param {number} x - X坐标
   * @param {number} y - Y坐标
   * @param {number} subdomain - 子域名索引 (0-7)
   * @returns {string} 瓦片URL
   */
  getTileUrl(type, z, x, y, subdomain = 0) {
    console.log(`===== 生成地图瓦片URL =====`);
    console.log(`地图类型: ${type}, 缩放级别: ${z}, 坐标: ${x}/${y}, 子域名: ${subdomain}`);
    
    if (!this.baseUrls[type]) {
      console.error(`不支持的地图类型: ${type}`);
      throw new Error(`不支持的地图类型: ${type}`);
    }
    
    const url = this.baseUrls[type]
      .replace('{s}', subdomain)
      .replace('{z}', z)
      .replace('{x}', x)
      .replace('{y}', y)
      .replace('{tk}', this.apiKey);
    
    // 打印URL但隐藏API密钥
    const maskedApiKey = this.apiKey ? this.apiKey.substring(0, 4) + '...' + this.apiKey.substring(this.apiKey.length - 4) : '';
    const maskedUrl = url.replace(this.apiKey, maskedApiKey);
    console.log(`生成的瓦片URL: ${maskedUrl}`);
    
    return url;
  }

  /**
   * 带重试机制的HTTP请求 - 增强版，实现更智能的退避策略
   * @param {string} url - 请求URL
   * @param {Object} options - 请求选项
   * @param {number} maxRetries - 最大重试次数
   * @param {number} baseDelay - 初始延迟时间（毫秒）
   * @returns {Promise} 请求结果
   */
  async fetchWithRetry(url, options, maxRetries = 5, baseDelay = 3000) {
    // 第一次尝试前增加随机延迟，避免请求风暴
    await new Promise(resolve => setTimeout(resolve, 500 + Math.random() * 1000));
    
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        console.log(`[tiandituService] 第${attempt}/${maxRetries}次尝试请求: ${url}`);
        return await axios.get(url, {
          ...options,
          timeout: 30000 // 增加超时时间到30秒
        });
      } catch (error) {
        // 如果是429错误且还有重试次数，延迟后重试
        if (error.response && error.response.status === 429 && attempt < maxRetries) {
          // 指数退避策略，每次重试时间增加，同时加入随机因素
          const backoffTime = baseDelay * Math.pow(2, attempt - 1) + Math.random() * 2000;
          console.log(`[tiandituService] 第${attempt}次请求失败(429)，${Math.round(backoffTime)}ms后重试...`);
          await new Promise(resolve => setTimeout(resolve, backoffTime));
        } else {
          // 输出详细错误信息，方便调试
          console.error(`[tiandituService] 请求失败${attempt === maxRetries ? '，已达最大重试次数' : ''}:`, 
              error.response ? `${error.response.status} ${error.response.statusText}` : error.message);
          throw error; // 其他错误或重试次数用尽，抛出异常
        }
      }
    }
  }

  /**
   * 获取地图瓦片数据
   * @param {string} type - 地图类型
   * @param {number} z - 缩放级别
   * @param {number} x - X坐标
   * @param {number} y - Y坐标
   * @param {string} mode - 工作模式 ('online' 或 'offline')
   * @returns {Promise<Buffer>} 瓦片数据
   */
  async fetchTile(type, z, x, y, mode = 'offline') {
    console.log(`===== 获取地图瓦片数据 =====`);
    console.log(`请求瓦片: ${type} ${z}/${x}/${y}`);
    console.log(`运行模式: ${mode}`);
    
    try {
      // 使用与代理路由相同的逻辑，只检查本地缓存
      const fs = require('fs-extra');
      const path = require('path');
      
      // 定义缓存目录路径
      const offlineMapDir = path.join(__dirname, '..', '..', 'offline-maps');
      
      // 根据地图类型确定路径和图层
      const mapTypeConfig = {
        vector: { path: 'vec_w', layer: 'vec' },
        vectorLabel: { path: 'cva_w', layer: 'cva' },
        image: { path: 'img_w', layer: 'img' },
        imageLabel: { path: 'cia_w', layer: 'cia' },
        terrain: { path: 'ter_w', layer: 'ter' },
        terrainLabel: { path: 'cta_w', layer: 'cta' }
      };
      
      const config = mapTypeConfig[type] || mapTypeConfig.vector;
      const { path: mapPath, layer } = config;
      
      // 确保参数正确
      const safeZ = String(z);
      const safeX = String(x);
      const safeY = String(y);
      const fileName = `${safeY}.png`;
      
      // 为每种地图类型定义单一明确的路径规则
      let tilePath;
      
      // 矢量图特殊处理 - 对应 offline-maps/vector/vector/{z}/{x}/{y}.png
      if (mapTypeConfig[type] && mapTypeConfig[type].path === 'vec_w' && mapTypeConfig[type].layer === 'vec') {
        tilePath = path.join(offlineMapDir, 'vector', 'vector', safeZ, safeX, fileName);
      }
      // 影像图特殊处理
      else if (mapTypeConfig[type] && mapTypeConfig[type].path === 'img_w' && mapTypeConfig[type].layer === 'img') {
        tilePath = path.join(offlineMapDir, 'vector', 'image', safeZ, safeX, fileName);
      }
      // 地形图特殊处理
      else if (mapTypeConfig[type] && mapTypeConfig[type].path === 'ter_w' && mapTypeConfig[type].layer === 'ter') {
        tilePath = path.join(offlineMapDir, 'vector', 'terrain', safeZ, safeX, fileName);
      }
      // 矢量注记特殊处理
      else if (mapTypeConfig[type] && mapTypeConfig[type].path === 'cva_w' && mapTypeConfig[type].layer === 'cva') {
        tilePath = path.join(offlineMapDir, 'vector', 'vectorLabel', safeZ, safeX, fileName);
      }
      // 影像注记特殊处理
      else if (mapTypeConfig[type] && mapTypeConfig[type].path === 'cia_w' && mapTypeConfig[type].layer === 'cia') {
        tilePath = path.join(offlineMapDir, 'vector', 'imageLabel', safeZ, safeX, fileName);
      }
      // 地形注记特殊处理
      else if (mapTypeConfig[type] && mapTypeConfig[type].path === 'cta_w' && mapTypeConfig[type].layer === 'cta') {
        tilePath = path.join(offlineMapDir, 'vector', 'terrainLabel', safeZ, safeX, fileName);
      }
      // 默认路径规则
      else {
        // 使用标准的代理缓存路径格式
        const cacheDir = path.join(offlineMapDir, 'proxy-cache');
        tilePath = path.join(cacheDir, mapPath, layer, safeZ, safeX, fileName);
      }
      
      console.log(`[tiandituService] 使用明确路径规则: ${tilePath}`);
      
      // 检查文件是否存在
      const fileExists = await fs.pathExists(tilePath);
      console.log(`[tiandituService] 检查文件: ${tilePath}, 存在: ${fileExists}`);
      
      if (fileExists) {
        // 验证是文件而不是目录
        const stat = await fs.stat(tilePath);
        if (stat.isFile()) {
          console.log(`[tiandituService] 文件存在且有效，大小: ${stat.size} 字节`);
          return await fs.readFile(tilePath);
        } else {
          console.log(`[tiandituService] 路径存在但不是文件: ${tilePath}`);
        }
      }
      
      // 缓存未命中
      console.log(`[tiandituService] 文件不存在: ${tilePath}`);
      
      // 根据模式决定后续行为
      if (mode === 'online') {
        console.log(`[tiandituService] 在线模式：尝试从天地图服务器获取瓦片`);
        // 构建瓦片URL并调用fetchWithRetry获取瓦片
        const tileUrl = this.getTileUrl(type, z, x, y);
        const response = await this.fetchWithRetry(tileUrl);
        
        // 保存到缓存
        try {
          // 确保目录存在
          await fs.ensureDir(path.dirname(tilePath));
          await fs.writeFile(tilePath, response.data);
          console.log(`[tiandituService] 瓦片已缓存到: ${tilePath}`);
        } catch (e) {
          console.error(`[tiandituService] 保存缓存失败:`, e.message);
        }
        
        return response.data;
      } else {
        console.log(`[tiandituService] 离线模式：直接返回透明瓦片`);
      }
      
      // 检查是否使用MBTiles
      if (process.env.USE_MBTILES === 'true' && global.mbtilesService) {
        console.log(`[tiandituService] 尝试从MBTiles获取瓦片`);
        try {
          const mbtilesTile = await global.mbtilesService.getTile(type, z, x, y);
          if (mbtilesTile) {
            console.log(`[tiandituService] 成功从MBTiles获取瓦片`);
            return mbtilesTile;
          }
        } catch (mbtilesError) {
          console.error(`[tiandituService] 从MBTiles获取瓦片失败:`, mbtilesError.message);
        }
      }
      
      // 透明PNG的Base64编码
      const TRANSPARENT_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==';
      return Buffer.from(TRANSPARENT_PNG_BASE64, 'base64');
      
    } catch (error) {
      console.error(`[tiandituService] 获取瓦片失败 ${type} ${z}/${x}/${y}:`, error.message);
      
      // 错误情况下也尝试从MBTiles获取
      if (process.env.USE_MBTILES === 'true' && global.mbtilesService) {
        try {
          const mbtilesTile = await global.mbtilesService.getTile(type, z, x, y);
          if (mbtilesTile) {
            console.log(`[tiandituService] 错误情况下从MBTiles获取瓦片成功`);
            return mbtilesTile;
          }
        } catch (mbtilesError) {
          console.error(`[tiandituService] 错误情况下从MBTiles获取瓦片也失败:`, mbtilesError.message);
        }
      }
      
      // 错误情况下也返回透明瓦片
      const TRANSPARENT_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==';
      return Buffer.from(TRANSPARENT_PNG_BASE64, 'base64');
    }
  }

  /**
   * 获取MapLibre GL样式配置
   * @param {string} baseLayer - 基础图层类型
   * @returns {Object} MapLibre GL样式配置
   */
  getMapStyle(baseLayer = 'vector') {
    console.log(`===== 获取MapLibre GL样式配置 =====`);
    console.log(`请求的基础图层类型: ${baseLayer}`);
    
    const layerConfigs = {
      vector: {
        path: 'vector',
        labelPath: 'vectorLabel'
      },
      image: {
        path: 'image',
        labelPath: 'imageLabel'
      },
      terrain: {
        path: 'terrain',
        labelPath: 'terrainLabel'
      }
    };

    const config = layerConfigs[baseLayer] || layerConfigs.vector;
    console.log(`实际使用的配置: ${JSON.stringify(config)}`);

    return {
      version: 8,
      sources: {
        'tianditu-base': {
          type: 'raster',
          tiles: [
            this.getTileUrl(config.path, '{z}', '{x}', '{y}', 0),
            this.getTileUrl(config.path, '{z}', '{x}', '{y}', 1),
            this.getTileUrl(config.path, '{z}', '{x}', '{y}', 2),
            this.getTileUrl(config.path, '{z}', '{x}', '{y}', 3),
            this.getTileUrl(config.path, '{z}', '{x}', '{y}', 4),
            this.getTileUrl(config.path, '{z}', '{x}', '{y}', 5),
            this.getTileUrl(config.path, '{z}', '{x}', '{y}', 6),
            this.getTileUrl(config.path, '{z}', '{x}', '{y}', 7)
          ],
          tileSize: 256,
          minzoom: 1,
          maxzoom: 18
        },
        'tianditu-label': {
          type: 'raster',
          tiles: [
            this.getTileUrl(config.labelPath, '{z}', '{x}', '{y}', 0),
            this.getTileUrl(config.labelPath, '{z}', '{x}', '{y}', 1),
            this.getTileUrl(config.labelPath, '{z}', '{x}', '{y}', 2),
            this.getTileUrl(config.labelPath, '{z}', '{x}', '{y}', 3),
            this.getTileUrl(config.labelPath, '{z}', '{x}', '{y}', 4),
            this.getTileUrl(config.labelPath, '{z}', '{x}', '{y}', 5),
            this.getTileUrl(config.labelPath, '{z}', '{x}', '{y}', 6),
            this.getTileUrl(config.labelPath, '{z}', '{x}', '{y}', 7)
          ],
          tileSize: 256,
          minzoom: 1,
          maxzoom: 18
        }
      },
      layers: [
        {
          id: 'tianditu-base-layer',
          type: 'raster',
          source: 'tianditu-base',
          layout: {
            visibility: 'visible'
          },
          paint: {}
        },
        {
          id: 'tianditu-label-layer',
          type: 'raster',
          source: 'tianditu-label',
          layout: {
            visibility: 'visible'
          },
          paint: {}
        }
      ],
      glyphs: '/data/demotiles/font/{fontstack}/{range}.pbf'
    };
  }

  /**
   * 获取离线地图样式配置
   * @param {string} mapType - 地图类型
   * @param {boolean} showLabels - 是否显示标注
   * @returns {Object} MapLibre GL样式配置
   */
  getOfflineMapStyle(mapType = 'vector', showLabels = true) {
    console.log(`===== 获取离线地图样式配置 =====`);
    console.log(`请求的地图类型: ${mapType}, 显示标注: ${showLabels}`);
    
    const layerConfigs = {
      vector: {
        basePath: 'vec_w',
        baseLayer: 'vec',
        labelPath: 'cva_w',
        labelLayer: 'cva'
      },
      image: {
        basePath: 'img_w',
        baseLayer: 'img',
        labelPath: 'cia_w',
        labelLayer: 'cia'
      },
      terrain: {
        basePath: 'ter_w',
        baseLayer: 'ter',
        labelPath: 'cta_w',
        labelLayer: 'cta'
      }
    };

    // 确保请求的地图类型有效，否则使用默认的矢量图
    const config = layerConfigs[mapType] || layerConfigs.vector;
    console.log(`实际使用的配置: ${JSON.stringify(config)}`);

    // 统一使用在线模式的URL格式，通过proxy-tile路由获取瓦片
    const baseUrlTemplate = `/api/map/proxy-tile/${config.basePath}/${config.baseLayer}/{z}/{x}/{y}.png`;
    const labelUrlTemplate = `/api/map/proxy-tile/${config.labelPath}/${config.labelLayer}/{z}/{x}/{y}.png`;
    
    console.log(`离线地图基础瓦片URL模板: ${baseUrlTemplate}`);
    console.log(`离线地图标签瓦片URL模板: ${labelUrlTemplate}`);
    
    const style = {
      version: 8,
      name: `天地图离线地图 - ${mapType === 'vector' ? '矢量图' : mapType === 'terrain' ? '地形图' : '影像图'}`,
      sources: {
        'tianditu-base': {
          type: 'raster',
          tiles: [baseUrlTemplate],
          tileSize: 256,
          minzoom: 1,
          maxzoom: 18,
          maxNativeZoom: 18, // 限制最大缩放级别
          tileCacheSize: 512 // 增加瓦片缓存大小
        }
      },
      layers: [
        {
          id: 'tianditu-base-layer',
          type: 'raster',
          source: 'tianditu-base',
          layout: {
            visibility: 'visible'
          },
          paint: {}
        }
      ],
      glyphs: '/data/demotiles/font/{fontstack}/{range}.pbf' // 使用本地字体文件
      // 暂时移除sprite配置以避免加载错误
    };
    
    // 如果需要显示标注，添加标注图层
    if (showLabels) {
      style.sources['tianditu-label'] = {
        type: 'raster',
        tiles: [labelUrlTemplate],
        tileSize: 256,
        minzoom: 1,
        maxzoom: 18
      };
      
      style.layers.push({
        id: 'tianditu-label-layer',
        type: 'raster',
        source: 'tianditu-label',
        layout: {
          visibility: 'visible'
        },
        paint: {}
      });
    }
    
    return style;
  }
}

module.exports = TiandituService;